//
// Created by 廖海龙 on 2025/4/8.
//

#ifndef HELLOVIDEOCACHE_HELLOVIDEOCACHESERVER_HPP
#define HELLOVIDEOCACHE_HELLOVIDEOCACHESERVER_HPP

// 系统库
#include <vector>
#include <thread>
#include <mutex>
#include <memory>
#include <atomic>
#include <unordered_map>
#include <unordered_set>



#include "HelloServerHelper.hpp"
#include "HelloHttpRequest.hpp"
#include "HelloBitStreamHandler.hpp"
#include "HelloPlaylistHandler.hpp"
#include "../log/Logger.hpp"
#include "../cache/HelloCacheManager.hpp"
#include "../cache/HelloCacheConfig.hpp"

/**
 * Author: liaohailong
 * Date: 2025/4/8
 * Time: 16:26
 * Description: 缓存代理服务器 socket + select
 *
 * 特殊情况:
 * 如果一个资源正在请求网络数据缓存至本地,另一个客户端(播放器)连接进来了,不是全命中本地缓存的话,就直接请求网络数据,不缓存本地
 *      确保客户端(播放器)能正常播放
 * 暂时不做特别精细化的处理,例如:两个url的range不冲突,分别缓存到分片文件上
 *      因为我们要把下载好的分片都给合并掉,下次播放器继续访问时,就好判断范围,也好取缓存,非并发的下载分片,合并大概率不会出错
 **/
class HelloVideoCacheServer
{
public:
    typedef struct
    {
        int maxfd; // select监听的最大fd数值
        fd_set read_set; // 需要监听的fd
        fd_set ready_set; // 当前可读的fd
        int nb_ready; // 可读fd的数量
        int maxi; // 客户端fd数组的有效长度
        int client_fds[FD_SETSIZE]; // 客户端fd数据,最多1024个
        rio_t client_rio[FD_SETSIZE]; // 客户端fd的健壮性io
        std::atomic<int> clients; // 已连接客户端数量
    } Pool;
public:
    explicit HelloVideoCacheServer(const char *tag = "HelloVideoCacheServerVictor");

    virtual ~HelloVideoCacheServer();

    void setConfig(const HelloCacheConfig &config);

    void start();

    std::string getProxyUrl(const std::string &url);

    void stop();

private:
    bool prepare();

    /**
     * @param p 初始化连接池
     */
    static void initPool(Pool *p, int listenFd);

    void releasePool(Pool *p);

    /**
     * @param p 连接池
     * @param connFd 新加入的
     * @return true表示添加成功
     */
    bool addClient(Pool *p, int connFd);

    void removeClient(Pool *p, int i);

    /**
     * @param p 检查 pool 中客户端可读事件
     */
    void checkClients(Pool *p);


private:
    void onClientServerReadable();

    void onClientRequest(const std::shared_ptr<HelloHttpRequest> &request);

    static std::string onUrlTransformer(const std::string &uri, void *userdata);

private:
    Logger logger;
    HelloCacheConfig config;
    std::shared_ptr<HelloCacheManager> cache;
    std::shared_ptr<HelloBitStreamHandler> bitstream;
    std::shared_ptr<HelloPlaylistHandler> playlist;
    int port;
    std::atomic<int> listenFd;

    Pool pool;
    std::atomic<bool> running;

    // 监听客户端连接
    std::thread *serverThread;
    std::unordered_map<int, std::string> clientBuffers;


};


#endif //HELLOVIDEOCACHE_HELLOVIDEOCACHESERVER_HPP
